﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.IO;
using XMLGener.Interfaces;

namespace XMLGener.Utils
{
    /// <summary>
    /// This class manages all modules instance and loads modules from DLLs.
    /// </summary>
    public class XModuleManager
    {
        /// <summary>
        /// This method loads modules instances from libraries, 
        /// which are located in directory "modules"
        /// </summary>
        public static void loadModules()
        {
            loadContentModules();
            loadOutputModules();
           
        }

        

        private static void loadOutputModules()
        {
            DirectoryInfo dir = new DirectoryInfo("modules");
            FileInfo[] fi= dir.GetFiles("*.dll");
            int max = fi.Length;

            TypeFilter XModulesFilter = new TypeFilter(XmlModulesInterfaceFilter);
            String[] interfacesFilterList = new String[1] { "XMLGener.Interfaces.XMLGenerOutputInterface" };
            modOutputList.Clear();
            //add empty module (for no output);
            modOutputList.Add("none",XModuleOutputInstance.getDefinitionInstance(null, null));
            string currentClass = null;
            for (int i = 0; i < max; i++)
            {

                try
                {
 
                    Assembly ass = Assembly.LoadFile(fi[i].FullName);
                    Type[] tps = ass.GetTypes();
                    foreach (Type t in tps)
                    {
                        if (t.IsClass && !t.IsAbstract)
                        {
                            currentClass = t.Name;
                            XMLGenerOutputInterface mif = ass.CreateInstance(fi[i].FullName) as XMLGenerOutputInterface;
                            Type[] filteredInterfaces = t.FindInterfaces(XModulesFilter, interfacesFilterList[0]);
                            if (filteredInterfaces.Length > 0)
                            {
                                XModuleOutputInstance inst = XModuleOutputInstance.getDefinitionInstance(ass, t);
                                if (inst != null)
                                {
                                    modOutputList.Add(inst.id,inst);
                                }
                            }
                        }
                    }
                }
                catch (Exception e)
                {

                    XLogger.addError("XModuleManager", "Loading " + currentClass + "(from " + fi[i].Name + ")" + e.Message);
                }
            }
        }

        private static void loadContentModules()
        {
            DirectoryInfo dir = new DirectoryInfo("modules");
            FileInfo[] fi= dir.GetFiles("*.dll");
            int max = fi.Length;

            TypeFilter XModulesFilter = new TypeFilter(XmlModulesInterfaceFilter);
            String[] interfacesFilterList = new String[1] { "XMLGener.Interfaces.XMLGenerModuleInterface" };

            string currentClass = null;
            for (int i = 0; i < max; i++)
            {

                try
                {
                    Assembly ass = Assembly.LoadFile(fi[i].FullName);
                    Type[] tps = ass.GetTypes();
                    foreach (Type t in tps)
                    {
                        if (t.IsClass && !t.IsAbstract)
                        {
                            currentClass = t.Name;
                            //XMLGenerModuleInterface mif = ass.CreateInstance(fi[i].FullName) as XMLGenerModuleInterface;
                            Type[] filteredInterfaces = t.FindInterfaces(XModulesFilter, interfacesFilterList[0]);
                            if (filteredInterfaces.Length > 0 &&
                                  t.FullName != typeof(XModuleInstance).FullName  && 
                                  t.FullName != typeof(XModuleDefinitionInstance).FullName)
                            {
                                XModuleDefinitionInstance inst = XModuleDefinitionInstance.getDefinitionInstance(ass, t);
                                if (inst != null)
                                {
                                    modDefinitionList.Add(inst.id, inst);
                                }
                            }
                        }
                    }
                }
                catch (Exception e)
                {

                    XLogger.addError("XModuleManager","Loading "+currentClass+"(from "+fi[i].Name+")" +e.Message);
                }

            }

        }

        /// <summary>
        /// List of modules instances, used just for getting module definition.
        /// </summary>
        public static Dictionary<string, XModuleOutputInstance> modOutputList = new Dictionary<string,XModuleOutputInstance>();


        /// <summary>
        /// List of modules instances, used just for getting module definition.
        /// </summary>
        public static Dictionary<string, XModuleDefinitionInstance> modDefinitionList = new Dictionary<string, XModuleDefinitionInstance>();


        /// <summary>
        /// List of modules templates. Used in generating modules.
        /// </summary>
        private static Dictionary<string, XModuleInstance> modInstancesList = new Dictionary<string, XModuleInstance>();

        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public static XModuleInstance getModuleInstance(string name)
        {
            if (!modDefinitionList.ContainsKey(name))
                return null;

            XModuleDefinitionInstance def = modDefinitionList[name];
            if (def==null) return null;
            XMLGenerModuleInterface coreInstance = def.createInstanceFromDLL();
            if (coreInstance == null) return null;
            return new XModuleInstance(coreInstance);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public static XMLGenerOutputInterface getOutputModuleInstance(string name)
        {
            if (!modOutputList.ContainsKey(name))
                return null;

            XModuleOutputInstance def = modOutputList[name];
            if (def == null) return null;
            return def.createInstanceFromDLL();
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="typeObj"></param>
        /// <param name="criteriaObj"></param>
        /// <returns></returns>
        private static bool XmlModulesInterfaceFilter(Type typeObj, Object criteriaObj)
        {
            if (typeObj.ToString() == criteriaObj.ToString())
                return true;
            else
                return false;
        }


    }
}
